package redis

import (
	"context"
	"fmt"
	"fruit/actor/iactor"

	"github.com/go-redis/redis/v8"
)

type Redis struct {
	ctx context.Context
	rdb *redis.Client
}

func Connect(addr string, pass string, db int32) *Redis {
	rds := new(Redis)
	rds.ctx = context.Background()

	rds.rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	return rds
}

func Subscribe(rds *Redis, channel string, psub bool, call iactor.IRedis_Sub) {
	if rds == nil || rds.rdb == nil {
		return
	}
	var sub *redis.PubSub
	if psub {
		sub = rds.rdb.PSubscribe(rds.ctx, channel)
	} else {
		sub = rds.rdb.Subscribe(rds.ctx, channel)
	}

	for {
		iface, err := sub.Receive(rds.ctx)
		if err != nil {
			// handle error
			fmt.Println("rds sub error", err)
			return
		}

		switch val := iface.(type) {
		case *redis.Subscription:
			// subscribe succeeded
			// fmt.Println("Subscription", val.Channel, val.Count, val.Kind)
			call.SubSuccess(val.Channel, val.Count, val.Kind)
		case *redis.Message:
			// received first message
			call.SubRecv(val.Channel, val.Pattern, val.Payload)
			// fmt.Println("Message", val.Channel, val.Pattern, val.Payload, val.PayloadSlice)
		case *redis.Pong:
			// pong received
			fmt.Println("Pong", val.Payload, val.String())
		default:
			// handle error
		}
	}
}

func Publish(rds *Redis, channel string, msg []byte) (int64, error) {
	if rds == nil || rds.rdb == nil {
		return 0, fmt.Errorf("rds or rdb empty")
	}

	resp := rds.rdb.Publish(rds.ctx, channel, msg)
	return resp.Result()
}

func Incr(rds *Redis, key string, num int64) (int64, error) {
	if rds == nil || rds.rdb == nil {
		return 0, fmt.Errorf("rds or rdb empty")
	}
	resp := rds.rdb.IncrBy(rds.ctx, key, num)
	return resp.Result()
}

func Do(rds *Redis, args ...interface{}) *redis.Cmd {
	if rds == nil || rds.rdb == nil {
		// return 0, fmt.Errorf("rds or rdb empty")
		return nil
	}
	resp := rds.rdb.Do(rds.ctx, args...)
	return resp
}

func Close(rds *Redis) {
	if rds != nil {
		rds.rdb.Close()
		rds.rdb = nil
	}
}
